package it.traveldream.beans;

import it.traveldream.dto.ExcursionDTO;
import it.traveldream.dto.LocationDTO;
import it.traveldream.dto.ProductDTO;
import it.traveldream.dto.ProductTypeDTO;
import it.traveldream.entities.Employee;
import it.traveldream.entities.Excursion;
import it.traveldream.entities.Location;
import it.traveldream.entities.ProductType;
import it.traveldream.exceptions.InvalidProductException;
import it.traveldream.exceptions.LocationNotFoundException;
import it.traveldream.exceptions.ProductNotFoundException;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.annotation.security.RolesAllowed;
import javax.ejb.Local;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 * Session Bean implementation class ExcursionManager
 */
@Stateless
@Local(ExcursionManagerInterface.class)
@LocalBean
public class ExcursionManager implements ExcursionManagerInterface {

	@PersistenceContext
	private EntityManager em;
	private Logger log;
    /**
     * Default constructor. 
     */
    public ExcursionManager() {
        super();
        this.log = Logger.getLogger(this.getClass().getSimpleName());
    }

	@Override
	@RolesAllowed({Employee.role})
	public List<ProductTypeDTO> getProductTypes() {
		@SuppressWarnings("unchecked")
		List<ProductType> types = this.em.createNamedQuery("getAllProductTypes").getResultList();
		
		ArrayList<ProductTypeDTO> typesDTO = new ArrayList<>();
		for (ProductType t : types){
			typesDTO.add(t.toDTO());
		}
		
		return typesDTO;
	}

	@Override
	@RolesAllowed({Employee.role})
	public List<ProductDTO> getProductsByLocation(LocationDTO location)
			throws LocationNotFoundException {

		TransportMeanManager m = new TransportMeanManager();
		return m.getProductsByLocation(location);
	}

	@Override
	@RolesAllowed({Employee.role})
	public ExcursionDTO getProduct(ProductDTO product)
			throws ProductNotFoundException {
		Long productId = product.getProductId();
		Excursion excursion = this.em.find(Excursion.class, productId);
		if (excursion == null){
			this.log.severe("ERROR: Problem while fetching excursion " + product.getName());
			throw new ProductNotFoundException();
		}
		
		return excursion.toDTO();
	}

	@Override
	@RolesAllowed({Employee.role})
	public ExcursionDTO saveProduct(ExcursionDTO product)
			throws InvalidProductException {
		Location l = this.em.find(Location.class, product.getLocation().getLocationId());
		Excursion excursion = new Excursion(product.getName(), l);
		
		try{
			excursion.setDuration(product.getDuration());
			excursion.setPrice(product.getPrice());
			excursion.setWeekDay(product.getWeekDay());
			
			this.em.persist(excursion);
			this.em.flush();
		} catch (Exception e){
			this.log.severe("ERROR: Problem while creating excursion " + product.getName());
			throw new InvalidProductException();
		}
		
		return excursion.toDTO();
	}

	@Override
	@RolesAllowed({Employee.role})
	public void updateProduct(ExcursionDTO product)
			throws ProductNotFoundException, InvalidProductException {
		Excursion excursion = this.em.find(Excursion.class, product.getProductId());
		if (excursion == null){
			this.log.severe("ERROR: Product " + product.getName() + " not found");
			throw new ProductNotFoundException();
		}
		
		try{
			Location l = this.em.find(Location.class, product.getLocation().getLocationId());
			excursion.setName(product.getName());
			excursion.setLocation(l);
			excursion.setDuration(product.getDuration());
			excursion.setPrice(product.getPrice());
			excursion.setWeekDay(product.getWeekDay());
			
			this.em.merge(excursion);
			this.em.flush();
		} catch (Exception e){
			this.log.severe("ERROR: Problem while updating excursion " + product.getName());
			throw new InvalidProductException();
		}
	}

	@Override
	@RolesAllowed({Employee.role})
	public void deleteProduct(ExcursionDTO product)
			throws ProductNotFoundException {
		Excursion excursion = this.em.find(Excursion.class, product.getProductId());
		
		if (excursion == null){
			this.log.severe("ERROR: Product " + product.getName() + " not found");
			throw new ProductNotFoundException();
		}
		try{
			this.em.remove(excursion);
			this.em.flush();
		} catch (Exception e){
			this.log.severe("ERROR: Problem while removing excursion " + product.getName());
			throw new RuntimeException();
		}	
	}

	@Override
	@RolesAllowed({Employee.role})
	public List<ExcursionDTO> getExcursionsByLocation(LocationDTO location)
			throws LocationNotFoundException {
		Location l = this.em.find(Location.class, location.getLocationId());
		if (l == null){
			this.log.severe("ERROR: Location " + location.getName() + " not found");
			throw new LocationNotFoundException();
		}
		
		@SuppressWarnings("unchecked")
		List<Excursion> products = 
        		this.em.createNamedQuery("getAllExcursionsInLocation").
        		setParameter("location", l).getResultList();
		
		ArrayList<ExcursionDTO> DTOs = new ArrayList<ExcursionDTO>();
		for (Excursion e : products){
			DTOs.add(e.toDTO());
		}
		return DTOs;
	}
}
